//
//  UIImage+NWGif.m
//  noworry
//
//  Created by dl on 2017/10/21.
//  Copyright © 2017年 dl. All rights reserved.
//

#import "UIImage+NWGif.h"
#import <BlocksKit/BlocksKit.h>
#import <BlocksKit/NSObject+BKAssociatedObjects.h>

@implementation UIImage (NWGif)

+ (UIImage *)nw_animatedGIFWithData:(NSData *)data {
    if (!data) {
        return nil;
    }
    
    NSMutableArray *durations = [@[] mutableCopy];
    
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    size_t count = CGImageSourceGetCount(source);
    UIImage *animatedImage;
    if (count <= 1) {
        animatedImage = [[UIImage alloc] initWithData:data];
    }
    else {
        NSMutableArray *images = [NSMutableArray array];
        NSTimeInterval sumDuration = 0.0f;
        for (size_t i = 0; i < count; i++) {
            CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
            if (!image) {
                continue;
            }
            
            NSTimeInterval duration =[self nw_frameDurationAtIndex:i source:source];
            if (!duration) {
                duration = 1.f / 10.f;
            }
            [durations addObject:@(duration)];
            
            sumDuration += duration;
            [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
            CGImageRelease(image);
        }
        animatedImage = [UIImage animatedImageWithImages:images duration:sumDuration];
    }
    [self bk_associateValue:@(count) withKey:KNWGifImageCountKey];
    [self bk_associateValue:durations withKey:KNWGifImageDurationsKey];
    CFRelease(source);
    
    return animatedImage;
}

+ (UIImage *)nw_animatedGIFNamed:(NSString *)name {
    CGFloat scale = [UIScreen mainScreen].scale;
    if (scale > 1.0f) {
        NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"];
        NSData *data = [NSData dataWithContentsOfFile:retinaPath];
        if (data) {
            return [UIImage nw_animatedGIFWithData:data];
        }
        
        NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
        data = [NSData dataWithContentsOfFile:path];
        if (data) {
            return [UIImage nw_animatedGIFWithData:data];
        }
        
        return [UIImage imageNamed:name];
    } else {
        NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
        NSData *data = [NSData dataWithContentsOfFile:path];
        if (data) {
            return [UIImage nw_animatedGIFWithData:data];
        }
        
        return [UIImage imageNamed:name];
    }
}

- (BOOL)nw_isGIF {
    return NO;
}

#pragma mark - private methods
+ (float)nw_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
    float frameDuration = 0.1f;
    CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
    NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
    NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
    
    NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
    if (delayTimeUnclampedProp) {
        frameDuration = [delayTimeUnclampedProp floatValue];
    }
    else {
        NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
        if (delayTimeProp) {
            frameDuration = [delayTimeProp floatValue];
        }
    }

    if (frameDuration < 0.011f) {
        frameDuration = 0.100f;
    }
    CFRelease(cfFrameProperties);
    return frameDuration;
}

#pragma mark - getters
static void *KNWGifImageCountKey = &KNWGifImageCountKey;

- (NSUInteger)nw_gifImageCount {
    return [[self bk_associatedValueForKey:KNWGifImageCountKey] unsignedIntegerValue];
}

static void *KNWGifImageDurationsKey = &KNWGifImageDurationsKey;
- (NSArray *)nw_gifDurations {
    return [self bk_associatedValueForKey:KNWGifImageDurationsKey];
}

@end
